import {cloneDeep} from 'lodash'
import utils from '../utils.js'

/**
 * 层管理器（用于接管楼层，注册所有楼层信息，一般是数据结构的最外层）
 */
export class LayerMgr {
  /**
   * 所有的字段私有化
   */

  #layers = []                       // 注册的所有楼层
  #layersMap = new Map()    // 楼层名称的字典
  #curLayerIdx = -1               // 激活楼层的序号

  /**
   * 通过属性暴露部分字段
   */

  get layers() {
    return this.#layers.slice()
  }

  get layersMap() {
    return new Map(this.#layersMap)
  }

  get curLayerIdx() {
    return this.#curLayerIdx
  }

  /**
   * 激活层的名称
   * @returns {*}
   */
  get curLayerName() {
    return this.#layers[this.#curLayerIdx]
  }

  /**
   * @param layers 初始化的层
   */
  constructor(layers = []) {
    if (!Array.isArray(layers)) {
      throw TypeError('The layers must be an array.')
    }

    // 检查层名称的唯一性
    const layersMap = new Map()
    for (const layer of layers) {
      if (layersMap.has(layer.name)) {
        throw Error(`The layer name ${layer.name} is exists.`)
      }

      layersMap.set(layer.name, layer)
    }

    this.#layersMap = layersMap
    this.#layers = layers

    // 设置激活层
    if (this.#layers.length > 0) {
      this.#curLayerIdx = 0
    }
  }

  /**
   * 激活层
   * @param layerIdx 层序号
   * @returns {LayerMgr}
   */
  setCurLayerByIdx(layerIdx) {
    if (!utils.isInTypes(layerIdx, ['string', 'number', 'bigint'])) {
      throw Error('The layerIdx must be a string or a number.')
    }

    const idx = utils.isString(layerIdx)
      ? parseInt(layerIdx, 10)
      : Number(layerIdx)

    if (idx < 0 || idx > this.#layers.length - 1) {
      throw Error(`The layerId ${layerIdx} is not valid.`)
    }

    this.#curLayerIdx = idx

    return this
  }

  /**
   * 激活层
   * @param layer 层实例
   * @returns {LayerMgr}
   */
  setCurLayer(layer) {
    if (!(layer instanceof Layer)) {
      throw TypeError('The layer must be an instance of Layer.')
    }

    const idx = this.#layers.indexOf(layer)
    if (idx === -1) {
      throw Error(`The layer not found.`)
    }

    this.#curLayerIdx = idx

    return this
  }
}

/**
 * 层的实体（用于存放物品）
 */
export class Layer {
  /**
   * 所有的字段私有化
   */

  #name = ''        // 层名称
  #items = []       // 层持有物品

  /**
   * 通过属性暴露部分字段
   */

  get name() {
    return this.#name
  }

  get items() {
    return this.#items.slice()
  }

  /**
   * @param name 层的名称
   * @param items 初始化的物品
   */
  constructor(name, items = []) {
    if (!utils.isString(name)) {
      throw TypeError('The Layer name must be a string.')
    }
    if (!Array.isArray(items)) {
      throw TypeError('The items must be an array.')
    }

    this.#name = name
    this.#items = items
  }

  /**
   * 放入物品
   * @param item 物品实例
   * @returns {Layer}
   */
  pushItem(item) {
    if (!(item instanceof Item)) {
      throw TypeError('The item must be an instance of Item.')
    }

    if (this.#items.indexOf(item) !== -1) {
      throw TypeError('The item is already in the layer.')
    }

    return this
  }

  /**
   * 移除物品
   * @param item 物品实例
   * @returns {Layer}
   */
  removeItem(item) {
    if (!(item instanceof Item)) {
      throw TypeError('The item must be an instance of Item.')
    }

    if (this.#items.indexOf(item) !== -1) {
      throw TypeError('The item is already in the layer.')
    }

    return this
  }

  /**
   * 清空物品
   */
  clearItems() {
    this.#items = []
  }
}

/**
 * 物品的实体
 */
export class Item {
  /**
   * 所有的字段私有化
   */

  #attrs = {}           // 物品属性
  #children = []     // 子物品

  /**
   * 通过属性暴露部分字段
   */

  get attrs() {
    return cloneDeep(this.#attrs)
  }

  get children() {
    return this.#children.slice()
  }

  constructor(attrs = {}, children = []) {
    if (!Array.isArray(children)) {
      throw TypeError('children must be an array')
    }

    this.#attrs = attrs
    this.#children = children
  }
}
